#include <utils/io.h>
#include <utils/bits.h>
#include <hw/console.h>
#include <hw/interrupts.h>

#define LEFT_SHIFT_CODE 42
#define RIGHT_SHIFT_CODE 54
#define CAPS_LOCK_CODE 58
#define CTRL_CODE 29

#define SHIFT_MODE 0x01
#define CTRL_MODE 0x02

#define SHIFT_OFFSET 100

char keymap[256] =
{
    0x00,    0x1b,    0x31,    0x32,    0x33,    0x34,    0x35,    0x36,    0x37,    0x38,
    0x39,    0x30,    0x27,    0xa8,    0x08,    0x09,    0x71,    0x77,    0x65,    0x72,
    0x74,    0x79,    0x75,    0x69,    0x6f,    0x70,    0x00,    0x2b,    0x0a,    0x00,
    0x61,    0x73,    0x64,    0x66,    0x67,    0x68,    0x6a,    0x6b,    0x6c,    0xa4,
    0x7b,    0x00,    0x00,    0x7d,    0x7a,    0x78,    0x63,    0x76,    0x62,    0x6e,
    0x6d,    0x2c,    0x2e,    0x2d,    0x00,    0x00,    0x00,    0x20,    0x00,    0x00,
    0x00,    0x00,    0x00,    0x00,    0x00,    0x00,    0x00,    0x00,    0x00,    0x00,
    0x00,    0x00,    0x00,    0x00,    0x00,    0x00,    0x00,    0x00,    0x00,    0x00,
    0x00,    0x00,    0x00,    0x00,    0x00,    0x00,    0x3c,    0x00,    0x00,    0x00,
    0x00,    0x00,    0x00,    0x00,    0x00,    0x00,    0x00,    0x00,    0x00,    0x00,
    0x00,    0x00,    0x21,    0x22,    0x23,    0x24,    0x25,    0x26,    0x2f,    0x28,
    0x29,    0x3d,    0x3f,    0xad,    0x00,    0x00,    0x51,    0x57,    0x45,    0x52,
    0x54,    0x59,    0x55,    0x49,    0x4f,    0x50,    0x00,    0x2a,    0x00,    0x00,
    0x41,    0x53,    0x44,    0x46,    0x47,    0x48,    0x4a,    0x4b,    0x4c,    0xa5,
    0x5b,    0x00,    0x00,    0x5d,    0x5a,    0x58,    0x43,    0x56,    0x42,    0x4e,
    0x4d,    0x3b,    0x3a,    0x5f,    0x00,    0x00,    0x00,    0x20,    0x00,    0x00,
    0x00,    0x00,    0x00,    0x00,    0x00,    0x00,    0x00,    0x00,    0x00,    0x00,
    0x00,    0x00,    0x00,    0x00,    0x00,    0x00,    0x00,    0x00,    0x00,    0x00,
    0x00,    0x00,    0x00,    0x00,    0x00,    0x00,    0x3e,    0x00,    0x00,    0x00,
};

struct {
    uint8 mode;
    uint8 leds;
} state;

void keyboard_release(uint8 scancode) {
    switch(scancode) {
        case LEFT_SHIFT_CODE:
        case RIGHT_SHIFT_CODE:
            CLEAR_BIT(state.mode, SHIFT_MODE);
            break;
        case CTRL_CODE:
            CLEAR_BIT(state.mode, CTRL_MODE);
            break;
    }
}

void keyboard_press(uint8 scancode) {
    switch(scancode) {
        case LEFT_SHIFT_CODE:
        case RIGHT_SHIFT_CODE:
            SET_BIT(state.mode, SHIFT_MODE);
            break;
        case CTRL_CODE:
            SET_BIT(state.mode, CTRL_MODE);
            break;
        case CAPS_LOCK_CODE:
            TOGGLE_BIT(state.mode, SHIFT_MODE);
            break;
        default:
            if(GET_BIT(state.mode, CTRL_MODE)){
                
            }else{
                uint8 shift_mode = GET_BIT(state.mode, SHIFT_MODE) ? 1 : 0;
                kputc(keymap[scancode + SHIFT_OFFSET * shift_mode]);
            }
    }
}

void keyboard_handler(struct interrupt_info info) {
    uint8 scancode;
    
    scancode = inb(0x60);

    if(scancode & 0x80) {
        /* Key release */
        CLEAR_BIT(scancode, 0x80);
        keyboard_release(scancode);
    } else {
        /* Key press */
        keyboard_press(scancode);
    }
}

void keyboard_init() {
    register_irq(1, &keyboard_handler);
}
